#ifndef CSERVER_PROTOCOL_H_
#define CSERVER_PROTOCOL_H_
#include <cserver/s11nbase.h>
#include <cserver/iom.h>
#include <vector>
#include <bitset>
namespace csrv{
	class buffer_in;

	typedef void (*load_fun)(buffer_in&, void* );
	template<typename T> void do_load(buffer_in& buf, void* dest){
		auto ar = s11n::as_source(buf);
		auto& p = *static_cast<T*>(dest);
		ar & p;
	}

#pragma pack(push, 1)
	struct HeadProtocol{
		uint32_t sig;
		uint8_t version;
		uint8_t	reserved;
		uint16_t cmd;
		uint16_t length;
	};

	struct HeadProtocolFire{
		uint16_t sig;
		uint16_t seq;
		uint8_t major_version;
		uint8_t user_version;
		uint32_t time4of6; 
	};
	static_assert(sizeof(HeadProtocol) == sizeof(HeadProtocolFire), "");
	struct fire_time {
		uint8_t second, minute, hour, day, month, year;
	};

	enum class HeadType{
		invalid,
		nbiot,
		fire,
	};
#pragma pack(pop)
	static const uint32_t K_signature = 0x5449424E;	//NBIT
	static const uint8_t K_version = 1;
	static const char K_reserved = 0;
	static const uint16_t K_sig_fire = 0x4040; // @@
	static const uint16_t K_sig_fire_end = 0x2323; // ##

	template<typename Ar> Ar& operator&(Ar& ar, fire_time& v){
		return ar & v.second & v.minute & v.hour & v.day 
			& v.month & v.year;
	}
	struct fire_package{
		uint16_t seq;
		fire_time time;
		std::array<char, 6> raw_src_addr, raw_dest_addr;
		std::string src_addr, dest_addr; // hex encoded 6 bytes
		std::vector<char> data;
		uint8_t command;
	};

	struct vector3f{
		float a, b, c;
	};
	template<typename Ar> Ar& operator&(Ar& ar, vector3f& v){
		return ar & v.a & v.b & v.c;
	}

	typedef vector3f pcm_meter_voltage;
	typedef vector3f pcm_meter_current;
	typedef vector3f pcm_meter_current_phase;

	struct pcm_meter_temperature{
		float a, b , c, d;
	};
	template<typename Ar> Ar& operator&(Ar& ar, pcm_meter_temperature& v){
		return ar & v.a & v.b & v.c & v.d;
	}

	struct pcm_meter_3phase_power {
		float active, reactive, apparent;
	};
	template<typename Ar> Ar& operator&(Ar& ar, pcm_meter_3phase_power& v){
		return ar & v.active & v.reactive & v.apparent;
	}

	struct pcm_meter_energy {
		int32_t forward_active, forward_reactive, reverse_active, reverse_reactive;
	};
	template<typename Ar> Ar& operator&(Ar& ar, pcm_meter_energy& v){
		return ar & v.forward_active & v.forward_reactive & v.reverse_active & v.reverse_reactive;
	}

	typedef vector3f pcm_meter_current_thd;
	typedef vector3f pcm_meter_voltage_thd;

	struct pcm_unbalance_factor {
		float voltage, current;
	};
	template<typename Ar> Ar& operator&(Ar& ar, pcm_unbalance_factor& v){
		return ar & v.voltage & v.current;
	}

	struct pcm_meter_self_test {
		uint16_t voltage_wire, current_wire, temperature_wire;
	};
	template<typename Ar> Ar& operator&(Ar& ar, pcm_meter_self_test& v){
		return ar & v.voltage_wire & v.current_wire & v.temperature_wire;
	}

	struct date_info {
		uint8_t month, year, hour, day, second, minute;
		uint16_t millisecond;
	};
	template<typename Ar> Ar& operator&(Ar& ar, date_info& v){
		return ar & v.month & v.year & v.hour & v.day 
			& v.second & v.minute & v.millisecond;
	}

	struct pcm_350a_data {
		std::string euid;
		uint8_t signal = 0;
		std::string simid;

		pcm_meter_voltage meter_voltage={}; //0x101
		pcm_meter_current meter_current={}; //0x102
		pcm_meter_current_phase meter_current_phase={}; //0x103

		float frequency = 0; //0x104
		float power_factor = 0;	//0x105
		pcm_meter_3phase_power meter_3phase_power={}; //0x106

		float base_residual_current = 0;	//0x107
		float fullwave_residual_current = 0;	//0x108

		uint16_t di_value = 0;  //0x109
		uint16_t do_value = 0;	//0x10a
		
		pcm_meter_temperature meter_temperature = {}; //0x10b
		pcm_meter_self_test meter_self_test = {}; //0x10c
		float total_harmonic_active_power = 0;	//0x10d
		pcm_meter_energy meter_energy = {}; //0x10e
		pcm_meter_current_thd meter_current_thd={}; // 0x10f
		pcm_meter_voltage_thd meter_voltage_thd={}; //0x110
		pcm_unbalance_factor unbalance_factor={}; //0x111
		date_info date = {}; //0x112
		uint16_t warning_code = 0; //0x113
	};


	struct pt_ct_init_data {
		uint32_t voltage_rating_first_side,
			  voltage_rating_second_side,
			  current_rating_first_side,
			  current_rating_second_side;
	};
	template<typename Ar> Ar& operator&(Ar& ar, pt_ct_init_data& v){
		return ar & v.voltage_rating_first_side & v.voltage_rating_second_side
			& v.current_rating_first_side & v.current_rating_second_side;
	}

	struct pcm_350a_init_data {
		pt_ct_init_data init_data = {}; //0x115
		uint16_t ct_type = 0; //0x116
		uint16_t wiring_type = 0; //0x117
		uint16_t do_value = 0;	//0x118
	};

	// PCM_350A_DeviceInitReturnData; //0x119


	struct pcm_threshold_setting {
		uint16_t triger_type, monitor_object;
		float triger_threshold_up, triger_threshold_down;
		uint16_t act_delay, return_delay, triger_act1, triger_act2;
	};
	template<typename Ar> Ar& operator&(Ar& ar, pcm_threshold_setting& v){
		return ar & v.triger_type & v.monitor_object 
			& v.triger_threshold_up & v.triger_threshold_down
			& v.act_delay & v.return_delay & v.triger_act1 & v.triger_act2;
	}

	//PCM_350A_Threshold_InitData // 0x11a
	//PCM_350A_Threshold_return value  // 0x11b
	//
	struct xhs_module_info {
		int32_t serial;
		uint32_t tele_operator;
		uint32_t station;
		int32_t signal;
		std::string netcard, module, module_type;
	};

	struct xhs_send_operation {
		int32_t serial;
		std::string module;
		uint32_t circuit, device_addr, channel, device_code, flag, vender, device_type, operation_code;
	};

	struct xhs_send_device_status {
		int32_t serial;
		std::string module;
		uint32_t circuit, device_addr, device_code, flag, vender ;
		std::vector<uint32_t> channel, device_type, devvice_status;
		int32_t signal;
	};

	struct xhs_send_anolog {
		int32_t serial;
		std::string module;
		uint32_t circuit, device_addr, flag, vender, device_code;
		std::vector<uint32_t> channel, device_type;
		std::vector<double> anolog_value;
		std::vector<uint32_t> device_status;
		int32_t signal;
	};

	struct xhs_send_anolog_config {
		int32_t serial;
		std::string module;
		uint32_t circuit, device_addr;
		std::vector<uint32_t> channel;
		uint32_t device_code, flag, vender;
		std::vector<uint32_t> device_type, signal_type, low_value, high_value;
		std::vector<std::string> unit;
	};


	// ============= fire ==============

	struct info_fire_facility_status{
		uint8_t sys_type, sys_addr;
		uint16_t status;
		fire_time time;
	};

	struct info_fire_part_status {
		uint8_t sys_type, sys_addr;
		uint8_t part_type;
		uint16_t part_area, part_number;

		uint16_t status;
		std::string description;
		fire_time time;
	};

	struct info_fire_part_analog {
		uint8_t sys_type, sys_addr;
		uint8_t part_type;
		uint16_t part_area, part_number;
		uint8_t value_type;
		int16_t value;
	};

	struct info_fire_facility_op_info {
		uint8_t sys_type, sys_addr;
		uint8_t op_flag, operator_id;
	};

	struct info_fire_facility_version {
		uint8_t sys_type, sys_addr;
		uint8_t major, minor;
	};

	struct info_fire_facility_config {
		uint8_t sys_type, sys_addr;
		std::string description;
	};

	struct info_fire_part_config {
		uint8_t sys_type, sys_addr;
		uint8_t part_type;
		uint16_t part_area, part_number;
		std::string description;
	};

	struct info_fire_facility_time {
		uint8_t sys_type, sys_addr;
		fire_time time;
	};

	struct info_fire_device_run_state{
		uint8_t status;
		fire_time time;
	};

	struct info_fire_device_op_info {
		uint8_t status, operator_id;
		fire_time time;
	};

	struct info_fire_device_version {
		uint8_t major, minor;
	};



	struct cmd_fire_get_status{
		static const uint8_t type=61;
		uint16_t sequence_id;
    	fire_time time;
		std::string src_addr, dest_arrd;
		uint8_t sys_type, sys_addr;
	};

	struct cmd_fire_get_part_status{
		static const uint8_t type=62;
		uint16_t sequence_id;
    	fire_time time;
		std::string src_addr, dest_arrd;
		uint8_t sys_type, sys_addr;
		uint16_t part_number, part_area;
	};

	struct cmd_fire_get_op_info{
		static const uint8_t type=64;
		uint16_t sequence_id;
    	fire_time time;
		std::string src_addr, dest_arrd;
		uint8_t sys_type, sys_addr;
		uint8_t count;
		fire_time start_time;
	};

	struct cmd_fire_get_version{
		static const uint8_t type=65;
		uint16_t sequence_id;
    	fire_time time;
		std::string src_addr, dest_arrd;
		uint8_t sys_type, sys_addr;
	};

	struct cmd_fire_get_config{
		static const uint8_t type=66;
		uint16_t sequence_id;
    	fire_time time;
		std::string src_addr, dest_arrd;
		uint8_t sys_type, sys_addr;
	};

	struct cmd_fire_get_part_config{
		static const uint8_t type=67;
		uint16_t sequence_id;
    	fire_time time;
		std::string src_addr, dest_arrd;
		uint8_t sys_type, sys_addr;
		uint16_t part_number, part_area;
	};

	struct cmd_fire_get_sys_time{
		static const uint8_t type=68;
		uint16_t sequence_id;
    	fire_time time;
		std::string src_addr, dest_arrd;
		uint8_t sys_type, sys_addr;
	};

	struct cmd_fire_get_run_status{
		static const uint8_t type=81;
		uint16_t sequence_id;
    	fire_time time;
		std::string src_addr, dest_arrd;
		uint8_t reserved;
	};

	struct cmd_fire_get_device_op_info{
		static const uint8_t type=84;
		uint16_t sequence_id;
    	fire_time time;
		std::string src_addr, dest_arrd;
		uint8_t count;
		fire_time start;
	};

	struct cmd_fire_get_device_version{
		static const uint8_t type=85;
		uint16_t sequence_id;
    	fire_time time;
		std::string src_addr, dest_arrd;
		uint8_t reserved;
	};

	struct cmd_fire_get_device_config{
		static const uint8_t type=86;
		uint16_t sequence_id;
    	fire_time time;
		std::string src_addr, dest_arrd;
		uint8_t reserved;
	};

	struct cmd_fire_get_device_time{
		static const uint8_t type=88;
		uint16_t sequence_id;
    	fire_time time;
		std::string src_addr, dest_arrd;
		uint8_t reserved;
	};

	struct cmd_fire_get_device_init{
		static const uint8_t type=89;
		uint16_t sequence_id;
    	fire_time time;
		std::string src_addr, dest_arrd;
		uint8_t reserved;
	};

	struct cmd_fire_sync_device_time{
		static const uint8_t type=90;
		uint16_t sequence_id;
    	fire_time time;
		std::string src_addr, dest_arrd;
		fire_time center_time;
	};

	struct cmd_fire_inspect{
		static const uint8_t type=91;
		uint16_t sequence_id;
    	fire_time time;
		std::string src_addr, dest_arrd;
		uint8_t minutes;
	};

	struct cmd_fire_get_made_time{
		static const uint8_t type=188;
		uint16_t sequence_id;
    	fire_time time;
		std::string src_addr, dest_arrd;
		uint8_t reserved;
	};

	struct cmd_fire_set_signup_time{
		static const uint8_t type=189;
		uint16_t sequence_id;
    	fire_time time;
		std::string src_addr, dest_arrd;
		fire_time center_time;
	};
	
	struct info_fire_pump_information {
		uint16_t cmd_id = 0x13;
		std::string ip_addr_port;
		std::string euid;
		uint32_t signal = 0;
		std::string sim_id;
		uint32_t voltage = 0;
		std::string ac_det;
	};

	struct info_waterater_data {
		std::string ip_addr_port;
		std::string euid, sim_id;
		uint32_t signal;
		int32_t voltage;
		float velocity;
		int32_t positive_cumulative_flow;
		int32_t negative_cumulative_flow;
		int32_t net_cumulative_flow;
		uint16_t error_code;
		uint16_t work_steps, upstream_signal,downstream_signal;
	};

/////// sponge city

	struct flow_meter {
		int32_t flow;
		int32_t flow_all;
		int16_t temperature;
		int16_t rate, depth;
	};

	struct ss_meter {
		int32_t ss;
		float factor;
		uint16_t humidity;
	};
	struct cod_meter {
		uint16_t cod, turbidity;
	};
	struct rain_meter {
		uint16_t hyetal, hyetal_all;
	};

	struct sponge_upconfig{
		std::string ip_addr_port;
		std::string euid, sim_id;
		uint32_t signal;
		uint32_t voltage;

		uint16_t sys_time_cond[4];
		uint16_t flow_cond[2];
		uint16_t cod_cond[2];
		uint16_t flow_cal_con;
	};

	struct sponge_downconfig{
		std::string ip_addr_port;
		std::string euid, sim_id;
		uint32_t signal;

		uint16_t sys_time_con[4];
		uint16_t sensor_use[4];
		uint16_t flow_cond[2];
		uint16_t cod_cond[2];
	};

	struct sponge_data{
		std::string ip_addr_port;
		std::string euid, sim_id;
		uint32_t signal;
		uint32_t voltage;

		uint16_t sensor_cond[4];

		flow_meter flow;
		ss_meter ss;
		cod_meter cod;
		rain_meter rain;
	};

}

#endif //end CSERVER_PROTOCOL_H_
